package utils

import (
	"archive/tar"
	"archive/zip"
	"compress/gzip"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
)

// zipFolder 递归地将文件夹内的所有文件压缩到ZIP文件中
func ZipFolder(sourceDir, targetZip string) error {

	// 如果目标文件已存在则删除
	if _, err := os.Stat(targetZip); err == nil {
		os.Remove(targetZip)
		fmt.Println("删除目标文件")
	}

	// 创建目标ZIP文件
	zipFile, err := os.Create(targetZip)
	if err != nil {
		return err
	}
	defer zipFile.Close()

	// 创建一个新的ZIP写入器
	zipWriter := zip.NewWriter(zipFile)
	defer zipWriter.Close()

	// 遍历文件夹并将所有文件添加到ZIP文件中
	return filepath.Walk(sourceDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		// 跳过文件夹
		if info.IsDir() {
			return nil
		}

		// 打开源文件
		file, err := os.Open(path)
		if err != nil {
			return err
		}
		defer file.Close()

		// 创建ZIP文件中的文件头
		header, err := zip.FileInfoHeader(info)
		if err != nil {
			return err
		}

		// 设置压缩方法
		header.Method = zip.Deflate

		// 设置文件在ZIP文件中的路径
		header.Name, err = filepath.Rel(sourceDir, path)
		if err != nil {
			return err
		}
		header.Name = strings.TrimPrefix(header.Name, string(filepath.Separator))

		// 创建ZIP文件中的文件
		writer, err := zipWriter.CreateHeader(header)
		if err != nil {
			return err
		}

		// 将源文件内容复制到ZIP文件中
		_, err = io.Copy(writer, file)
		return err
	})
}

// moveAndUnzip 将压缩文件移动到指定目录并解压缩
func MoveAndUnzip(zipFilePath, targetDir string) error {
	// 创建目标目录（如果不存在）
	if err := os.MkdirAll(targetDir, 0755); err != nil {
		return err
	}

	// 移动压缩文件到目标目录
	newZipFilePath := filepath.Join(targetDir, filepath.Base(zipFilePath))
	if err := os.Rename(zipFilePath, newZipFilePath); err != nil {
		return err
	}

	// 解压缩文件
	return Unzip(newZipFilePath, targetDir)
}

// unzip 解压缩ZIP文件到指定目录
func Unzip(zipFilePath, targetDir string) error {
	// 打开ZIP文件
	r, err := zip.OpenReader(zipFilePath)
	if err != nil {
		return err
	}
	defer r.Close()

	// 遍历ZIP文件中的所有文件并解压缩
	for _, f := range r.File {
		err := UnzipFile(f, targetDir)
		if err != nil {
			return err
		}
	}

	return nil
}

// unzipFile 解压缩单个文件
func UnzipFile(f *zip.File, targetDir string) error {
	// 打开ZIP文件中的文件
	rc, err := f.Open()
	if err != nil {
		return err
	}
	defer rc.Close()

	// 创建目标文件路径
	path := filepath.Join(targetDir, f.Name)

	// 如果是目录，创建目录
	if f.FileInfo().IsDir() {
		os.MkdirAll(path, f.Mode())
		return nil
	}

	// 创建目标文件的父目录
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return err
	}

	// 创建目标文件
	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
	if err != nil {
		return err
	}
	defer file.Close()

	// 将ZIP文件中的内容复制到目标文件
	_, err = io.Copy(file, rc)
	return err
}

// 读取文件内容
func ReadFile(path string) ([]byte, error) {
	file, err := os.Open(path)
	if err != nil {
		return []byte{}, err
	}
	defer file.Close()
	fileInfo, err := file.Stat()
	if err != nil {
		return []byte{}, err
	}
	buf := make([]byte, fileInfo.Size())
	_, err = file.Read(buf)
	if err != nil {
		return []byte{}, err
	}
	return buf, err
}

/**
 * 压缩目录 tar
 * @param inputDir 输入目录
 * @param outputPath 输出文件路径
 * @return error
 */
func CompressDirectory(inputDir string, outputPath string) error {
	outputFile, err := os.Create(outputPath)
	if err != nil {
		return err
	}
	defer outputFile.Close()

	gzipWriter := gzip.NewWriter(outputFile)
	defer gzipWriter.Close()

	tarWriter := tar.NewWriter(gzipWriter)
	defer tarWriter.Close()

	return filepath.Walk(inputDir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}

		header, err := tar.FileInfoHeader(info, info.Name())
		if err != nil {
			return err
		}

		header.Name = filepath.ToSlash(path)

		if err := tarWriter.WriteHeader(header); err != nil {
			return err
		}

		if !info.IsDir() {
			file, err := os.Open(path)
			if err != nil {
				return err
			}
			defer file.Close()

			_, err = io.Copy(tarWriter, file)
			return err
		}

		return nil
	})
}

// 判断文件是否存在
func FileExists(filename string) bool {
	_, err := os.Stat(filename)
	if os.IsNotExist(err) {
		return false
	}
	return err == nil
}
